/* Copyright 2008 Mike Mammarella. Released under GPLv2. */

/* THIS FILE CONTAINS A TERRIBLE HACK */

/* Had WPAD_SetLeds() been defined in wpad.c, it would not be a terrible hack.
 * But to do it elsewhere, we need access to the wiimote_t structures created by
 * the call to wiiuse_init() and stored in the variable __wpads in wpad.c. Alas,
 * there seems to be no way to get a pointer to them through the normal API (the
 * closest is the "flags" field in nunchuk_t, which through some simple pointer
 * arithmetic can get to the wiimote_t structures, but then you have to connect
 * a nunchuk). */

/* So, to get the wiimote_t structures here, we include __wpads.h which is
 * generated by the "compile" script using the address of __wpads found with nm
 * on the final ELF file. Initially we have NULL for the address just to get
 * everything else to compile, and then we revise it and recompile. Since it's
 * just a constant changing, the addresses of all the symbols stay the same, and
 * we will get a consistent build. */

/* keep the "leds" field from being const */
#define WIIUSE_INTERNAL_H_INCLUDED
#include <wiiuse/wpad.h>

#include "wpad_leds.h"

/* get __WPADS_ADDR */
#include "__wpads.h"

/* copied from wiiuse_internal.h */
#define WIIMOTE_STATE_RUMBLE 0x00080
#define WIIMOTE_IS_SET(wm, s) ((wm->state & (s)) == (s))
#define WIIMOTE_ENABLE_STATE(wm, s) (wm->state |= (s))
#define WIIMOTE_DISABLE_STATE(wm, s) (wm->state &= ~(s))

s32 WPAD_SetLeds(s32 chan, int leds)
{
	/* THIS IS A HACK... A TERRIBLE HACK */
	struct wiimote_t ** __wpads = *((struct wiimote_t ***) __WPADS_ADDR);
	struct wiimote_t * wm;
	int rumble;
	
	if(chan < WPAD_CHAN_0 || chan >= WPAD_MAX_WIIMOTES)
		return WPAD_ERR_BAD_CHANNEL;
	
	/* change the LED status in the wiimote_t structure */
	wm = __wpads[chan];
	wm->leds = leds & 0xF0;
	
	/* get the command sent to the wiimote by resending rumble */
	rumble = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE);
	if(rumble)
		WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_RUMBLE);
	else
		WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_RUMBLE);
	return WPAD_Rumble(chan, rumble);
}

